use std::collections::HashSet;
-use std::io::{Write, BufWriter};
-use std::fs::File;
+use std::io::{Write, BufWriter, ErrorKind};
+use std::fs::{self, File};
use std::path::{Path, PathBuf};
use ops::{Context, Unit};
fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<'a, 'b>,
unit: &Unit<'a>, visited: &mut HashSet<Unit<'a>>) -> CargoResult<()>
{
- if visited.contains(unit) {
+ if !visited.insert(unit.clone()) {
return Ok(());
}
- visited.insert(unit.clone());
// Add dependencies from rustc dep-info output (stored in fingerprint directory)
let dep_info_loc = fingerprint::dep_info_loc(context, unit);
for path in paths {
deps.insert(path);
}
+ } else {
+ debug!("can't find dep_info for {:?} {:?}",
+ unit.pkg.package_id(), unit.profile);
+ return Err(internal("dep_info missing"));
}
// Add rerun-if-changed dependencies
pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> {
let mut deps = HashSet::new();
let mut visited = HashSet::new();
- add_deps_for_unit(&mut deps, context, unit, &mut visited)?;
+ let success = add_deps_for_unit(&mut deps, context, unit, &mut visited).is_ok();
let basedir = None; // TODO
for (_filename, link_dst, _linkable) in context.target_filenames(unit)? {
if let Some(link_dst) = link_dst {
let output_path = link_dst.with_extension("d");
- let target_fn = render_filename(link_dst, basedir)?;
- let mut outfile = BufWriter::new(File::create(output_path)?);
- write!(outfile, "{}:", target_fn)?;
- for dep in &deps {
- write!(outfile, " {}", render_filename(dep, basedir)?)?;
+ if success {
+ let mut outfile = BufWriter::new(File::create(output_path)?);
+ let target_fn = render_filename(link_dst, basedir)?;
+ write!(outfile, "{}:", target_fn)?;
+ for dep in &deps {
+ write!(outfile, " {}", render_filename(dep, basedir)?)?;
+ }
+ writeln!(outfile, "")?;
+ } else {
+ // dep-info generation failed, so delete output file. This will usually
+ // cause the build system to always rerun the build rule, which is correct
+ // if inefficient.
+ match fs::remove_file(output_path) {
+ Err(err) => {
+ if err.kind() != ErrorKind::NotFound {
+ return Err(err.into());
+ }
+ }
+ _ => ()
+ }
}
- writeln!(outfile, "")?;
}
}
Ok(())
--- /dev/null
+extern crate cargotest;
+extern crate hamcrest;
+
+use cargotest::support::{basic_bin_manifest, main_file, execs, project};
+use hamcrest::{assert_that, existing_file};
+
+#[test]
+fn build_dep_info() {
+ let p = project("foo")
+ .file("Cargo.toml", &basic_bin_manifest("foo"))
+ .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));
+
+ assert_that(p.cargo_process("build"), execs().with_status(0));
+
+ let depinfo_bin_path = &p.bin("foo").with_extension("d");
+
+ assert_that(depinfo_bin_path, existing_file());
+}
+
+#[test]
+fn build_dep_info_lib() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [[example]]
+ name = "ex"
+ crate-type = ["lib"]
+ "#)
+ .file("src/lib.rs", "")
+ .file("examples/ex.rs", "");
+
+ assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
+ assert_that(&p.example_lib("ex", "lib").with_extension("d"), existing_file());
+}
+
+
+#[test]
+fn build_dep_info_rlib() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [[example]]
+ name = "ex"
+ crate-type = ["rlib"]
+ "#)
+ .file("src/lib.rs", "")
+ .file("examples/ex.rs", "");
+
+ assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
+ assert_that(&p.example_lib("ex", "rlib").with_extension("d"), existing_file());
+}
+
+#[test]
+fn build_dep_info_dylib() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [[example]]
+ name = "ex"
+ crate-type = ["dylib"]
+ "#)
+ .file("src/lib.rs", "")
+ .file("examples/ex.rs", "");
+
+ assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0));
+ assert_that(&p.example_lib("ex", "dylib").with_extension("d"), existing_file());
+}